home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC Graphics Unleashed
/
PC Graphics Unleashed.iso
/
ch03
/
color.c
next >
Wrap
C/C++ Source or Header
|
1993-05-21
|
7KB
|
237 lines
/****************************************************************
* FILE: color.c
* DESC: This file contains the color routines used by morph,
* dissolve and fix.
*
* HISTORY: Created 3/18/1993
* LAST CHANGED: 5/ 6/1993
*
* Copyright (c) 1992 by Scott Anderson
*
****************************************************************/
#include <stdio.h>
#include <memory.h>
#include "define.h"
/* ----------------------DEFINES------------------------------ */
/* ----------------------TYPEDEFS/STRUCTS--------------------- */
/* ----------------------PROTOTYPES--------------------------- */
int closestColor(int r, int g, int b, PALETTE *palPtr);
void collapseColors(PALETTE *palPtr);
int mergePalette(PICTURE *pic);
int remapPicture(PICTURE *picPtr, PALETTE *palPtr);
int initFreq();
/* ----------------------EXTERNALS---------------------------- */
/* set from last picture loaded */
extern int Xmin, Ymin, Xmax, Ymax;
/* ----------------------GLOBAL DATA-------------------------- */
/* number of colors in tweened image before reduction*/
int Ncolors;
/* r, g, b frequency counter array */
unsigned int far Freq[MAX_COMP][MAX_COMP][MAX_COMP];
/* tweened images red, grn, and blu components*/
unsigned char far Red[MAX_WIDE][MAX_TALL];
unsigned char far Grn[MAX_WIDE][MAX_TALL];
unsigned char far Blu[MAX_WIDE][MAX_TALL];
PALETTE TweenPal; /* resulting palette */
/*****************************************************************
* FUNC: void collapseColors(PALETTE *palPtr)
*
* DESC: Collapse the colors in the Freq table until
* Ncolors < COLORS, then put it in the given color palette.
*****************************************************************/
void
collapseColors(PALETTE *palPtr)
{
int freqCutoff;
int r, g, b;
int index;
int ncolors;
static int freqCount[MAX_FREQ+1];
memset(freqCount, 0, sizeof freqCount);
for (r = 0; r < MAX_COMP; r++)
for (g = 0; g < MAX_COMP; g++)
for (b = 0; b < MAX_COMP; b++)
freqCount[Freq[r][g][b]]++;
ncolors = 0;
for (freqCutoff = COLORS-1; freqCutoff > 1; freqCutoff--) {
ncolors += freqCount[freqCutoff];
if (ncolors > COLORS) break;
}
/* Collapse color space to 256 colors */
r = g = b = 0;
while (Ncolors >= COLORS) {
for (; r < MAX_COMP; r++, g=0) {
for (; g < MAX_COMP; g++, b=0) {
for (; b < MAX_COMP; b++) {
if (Freq[r][g][b] && Freq[r][g][b]
<= freqCutoff)
goto castOut; /* the ultimate no no */
}
}
}
r = g = b = 0;
freqCutoff++;
continue;
castOut:
Freq[r][g][b] = 0; /* just remove this low freq color */
Ncolors--;
}
/* build a palette out of all the remaining non zero freq's */
index = 0;
for (r = 0; r < MAX_COMP; r++)
for (g = 0; g < MAX_COMP; g++)
for (b = 0; b < MAX_COMP; b++)
/* we have a color we need to map */
if (Freq[r][g][b]) {
palPtr->c[index].r = r;
palPtr->c[index].g = g;
palPtr->c[index].b = b;
/* remember index in palette */
Freq[r][g][b] = index;
index++;
}
}
/*****************************************************************
* FUNC: int closestColor(int r, int g, int b, PALETTE *palPtr)
*
* DESC: return the palette index of the color closest to rgb.
*****************************************************************/
int
closestColor(int r, int g, int b, PALETTE *palPtr)
{
int index;
int distance;
int min_distance = 3200; /* a big number */
int min_index;
/* The value in Freq is now the index into the color table */
if (Freq[r][g][b]) return Freq[r][g][b];
/* If zero, search for the closest color */
for (index = 1; index < Ncolors; index++) {
/* this is really the distance squared, but it works */
distance = SQUARE (r - palPtr->c[index].r) +
SQUARE (g - palPtr->c[index].g) +
SQUARE (b - palPtr->c[index].b);
if (distance < min_distance) {
min_distance = distance;
min_index = index;
if (distance <= 2) break; /* close enough! */
}
}
/* New index - for future reference */
Freq[r][g][b] = min_index;
return min_index;
}
/*****************************************************************
* FUNC: int mergePalette(PICTURE *picPtr)
*
* DESC: Merge a palette into Freq count table.
*****************************************************************/
int
mergePalette(PICTURE *picPtr)
{
int r, g, b;
unsigned int pos;
unsigned char index;
PALETTE *palPtr = &picPtr->pal;
unsigned char far *bufPtr = picPtr->pixmap;
for (pos = 0; pos < MAX_BYTES; pos++) {
index = *bufPtr++;
r = palPtr->c[index].r;
g = palPtr->c[index].g;
b = palPtr->c[index].b;
if (Freq[r][g][b] == 0) /* A new color */
Ncolors++;
if (Freq[r][g][b] < MAX_FREQ) /* Keep it managable */
Freq[r][g][b]++;
}
}
/*****************************************************************
* FUNC: int remapPicture(PICTURE *picPtr, PALETTE *palPtr)
*
* DESC: Remap a picture with a different palette.
*****************************************************************/
int
remapPicture(PICTURE *picPtr, PALETTE *palPtr)
{
int x, y;
int index;
int r, g, b;
unsigned int pos;
unsigned char lookup[COLORS];
unsigned char far *bufPtr;
/* Create the cross-reference lookup table */
for (index = 0; index < COLORS; index++) {
r = picPtr->pal.c[index].r;
g = picPtr->pal.c[index].g;
b = picPtr->pal.c[index].b;
lookup[index] = closestColor(r, g, b, palPtr);
}
/* Save the new palette in the picture's palette */
for (index = 0; index < COLORS; index++) {
picPtr->pal.c[index].r = palPtr->c[index].r;
picPtr->pal.c[index].g = palPtr->c[index].g;
picPtr->pal.c[index].b = palPtr->c[index].b;
}
/* Remap the individual pixels to point to the new colors */
for (bufPtr = picPtr->pixmap, pos = 0; pos < MAX_BYTES;
bufPtr++, pos++)
*bufPtr = lookup[*bufPtr];
}
/*****************************************************************
* FUNC: int initFreq()
*
* DESC: zero out the frequency color space table
*****************************************************************/
int
initFreq()
{
int bytes = (sizeof Freq) / 2;
_fmemset(Freq, 0, bytes);
/* divide because of element size */
_fmemset(Freq+(bytes/sizeof *Freq), 0, bytes);
/* Guarantee a black color */
Freq[0][0][0] = MAX_FREQ;
/* a grey color */
Freq[MID_COMP-1][MID_COMP-1][MID_COMP-1] = MAX_FREQ;
/* and a white color */
Freq[(long)MAX_COMP-1][MAX_COMP-1][MAX_COMP-1] = MAX_FREQ;
Ncolors = 3;
}